﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.Election.KingdomDecision
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem.CharacterDevelopment;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem.Election
{
  public abstract class KingdomDecision
  {
    [SaveableField(0)]
    private static bool _notificationsEnabled = true;
    [SaveableField(1)]
    private bool _isEnforced;
    [SaveableField(2)]
    private bool _playerExamined;
    private bool _notifyPlayer = KingdomDecision._notificationsEnabled;
    [SaveableField(10)]
    private Kingdom _kingdom;
    public KingdomDecision.SupportStatus SupportStatusOfFinalDecision;

    protected virtual void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      collectedObjects.Add((object) this._kingdom);
      collectedObjects.Add((object) this.ProposerClan);
      CampaignTime.AutoGeneratedStaticCollectObjectsCampaignTime((object) this.TriggerTime, collectedObjects);
    }

    internal static object AutoGeneratedGetMemberValueProposerClan(object o)
    {
      return (object) ((KingdomDecision) o).ProposerClan;
    }

    internal static object AutoGeneratedGetMemberValueTriggerTime(object o)
    {
      return (object) ((KingdomDecision) o).TriggerTime;
    }

    internal static object AutoGeneratedGetMemberValue_isEnforced(object o)
    {
      return (object) ((KingdomDecision) o)._isEnforced;
    }

    internal static object AutoGeneratedGetMemberValue_playerExamined(object o)
    {
      return (object) ((KingdomDecision) o)._playerExamined;
    }

    internal static object AutoGeneratedGetMemberValue_kingdom(object o)
    {
      return (object) ((KingdomDecision) o)._kingdom;
    }

    public Kingdom Kingdom => this._kingdom ?? this.ProposerClan.Kingdom;

    [SaveableProperty(4)]
    public Clan ProposerClan { get; private set; }

    public bool IsEnforced
    {
      get => this._isEnforced;
      set => this._isEnforced = value;
    }

    public bool PlayerExamined
    {
      get => this._playerExamined;
      set => this._playerExamined = value;
    }

    public bool NotifyPlayer
    {
      get => this._notifyPlayer || this.IsEnforced;
      set => this._notifyPlayer = value;
    }

    public bool IsPlayerParticipant
    {
      get => this.Kingdom == Clan.PlayerClan.Kingdom && !Clan.PlayerClan.IsUnderMercenaryService;
    }

    [SaveableProperty(3)]
    public CampaignTime TriggerTime { get; protected set; }

    protected KingdomDecision(Clan proposerClan)
    {
      this.ProposerClan = proposerClan;
      this._kingdom = proposerClan.Kingdom;
      this.TriggerTime = CampaignTime.HoursFromNow((float) this.HoursToWait);
    }

    public virtual bool IsKingsVoteAllowed => true;

    public abstract bool IsAllowed();

    public int GetInfluenceCost(Clan sponsorClan)
    {
      int proposalInfluenceCost = this.GetProposalInfluenceCost();
      return sponsorClan != Clan.PlayerClan ? proposalInfluenceCost : proposalInfluenceCost;
    }

    public abstract int GetProposalInfluenceCost();

    public abstract TextObject GetGeneralTitle();

    public abstract TextObject GetSupportTitle();

    public abstract TextObject GetChooseTitle();

    public abstract TextObject GetSupportDescription();

    public abstract TextObject GetChooseDescription();

    public virtual float CalculateMeritOfOutcome(DecisionOutcome candidateOutcome) => 1f;

    public abstract IEnumerable<DecisionOutcome> DetermineInitialCandidates();

    public MBList<DecisionOutcome> NarrowDownCandidates(
      MBList<DecisionOutcome> initialCandidates,
      int maxCandidateCount)
    {
      foreach (DecisionOutcome initialCandidate in (List<DecisionOutcome>) initialCandidates)
        initialCandidate.InitialMerit = this.CalculateMeritOfOutcome(initialCandidate);
      return this.SortDecisionOutcomes((MBReadOnlyList<DecisionOutcome>) initialCandidates).Take<DecisionOutcome>(maxCandidateCount).ToMBList<DecisionOutcome>();
    }

    public abstract Clan DetermineChooser();

    public IEnumerable<Supporter> DetermineSupporters()
    {
      foreach (Clan clan in (List<Clan>) this.Kingdom.Clans)
      {
        if (!clan.IsUnderMercenaryService)
          yield return new Supporter(clan);
      }
    }

    protected virtual bool ShouldBeCancelledInternal() => false;

    protected virtual bool CanProposerClanChangeOpinion() => false;

    public bool ShouldBeCancelled()
    {
      if (this.ProposerClan.Kingdom != this.Kingdom || !this.IsAllowed() || this.ShouldBeCancelledInternal())
        return true;
      if (this.ProposerClan == Clan.PlayerClan)
        return false;
      MBList<DecisionOutcome> mbList = this.NarrowDownCandidates(this.DetermineInitialCandidates().ToMBList<DecisionOutcome>(), 3);
      DecisionOutcome queriedDecisionOutcome = this.GetQueriedDecisionOutcome((MBReadOnlyList<DecisionOutcome>) mbList);
      this.DetermineSponsors((MBReadOnlyList<DecisionOutcome>) mbList);
      Supporter.SupportWeights supportWeightOfSelectedOutcome;
      DecisionOutcome supportOption = this.DetermineSupportOption(new Supporter(this.ProposerClan), (MBReadOnlyList<DecisionOutcome>) mbList, out supportWeightOfSelectedOutcome, true);
      bool flag1 = (double) this.ProposerClan.Influence < (double) this.GetInfluenceCostOfSupport(this.ProposerClan, Supporter.SupportWeights.SlightlyFavor) * 1.5;
      int num = mbList.Any<DecisionOutcome>((Func<DecisionOutcome, bool>) (t => t.SponsorClan != null && t.SponsorClan.IsEliminated)) ? 1 : 0;
      bool flag2 = supportWeightOfSelectedOutcome == Supporter.SupportWeights.StayNeutral || supportOption == null;
      bool flag3 = supportOption != queriedDecisionOutcome || supportOption == queriedDecisionOutcome & flag2;
      if (num != 0)
        return true;
      if (!mbList.Any<DecisionOutcome>((Func<DecisionOutcome, bool>) (t => t.SponsorClan == this.ProposerClan)) || flag1)
        return false;
      return !this.CanProposerClanChangeOpinion() & flag3 || this.CanProposerClanChangeOpinion() & flag2;
    }

    protected virtual int HoursToWait => 48;

    public bool NeedsPlayerResolution
    {
      get
      {
        if (this.Kingdom != Clan.PlayerClan.Kingdom)
          return false;
        if (this.IsEnforced)
          return true;
        return this.TriggerTime.IsPast && this.Kingdom.RulingClan == Clan.PlayerClan;
      }
    }

    public DecisionOutcome DetermineSupportOption(
      Supporter supporter,
      MBReadOnlyList<DecisionOutcome> possibleOutcomes,
      out Supporter.SupportWeights supportWeightOfSelectedOutcome,
      bool calculateRelationshipEffect)
    {
      Supporter.SupportWeights supportWeight = Supporter.SupportWeights.Choose;
      DecisionOutcome decisionOutcome1 = (DecisionOutcome) null;
      DecisionOutcome decisionOutcome2 = (DecisionOutcome) null;
      float num1 = float.MinValue;
      float num2 = 0.0f;
      int num3 = 0;
      Clan clan = supporter.Clan;
      foreach (DecisionOutcome possibleOutcome in (List<DecisionOutcome>) possibleOutcomes)
      {
        float support = this.DetermineSupport(supporter.Clan, possibleOutcome);
        if ((double) support > (double) num1)
        {
          decisionOutcome1 = possibleOutcome;
          num1 = support;
        }
        if ((double) support < (double) num2)
        {
          decisionOutcome2 = possibleOutcome;
          num2 = support;
        }
        ++num3;
      }
      if (decisionOutcome1 != null)
      {
        float num4 = num1;
        if (decisionOutcome2 != null)
          num4 -= 0.5f * num2;
        float num5 = num4;
        if ((double) clan.Influence < (double) num5 * 2.0)
        {
          num5 *= 0.5f;
          if ((double) num5 > (double) clan.Influence * 0.699999988079071)
            num5 = clan.Influence * 0.7f;
        }
        else if ((double) clan.Influence > (double) num5 * 10.0)
          num5 *= 1.5f;
        if ((double) decisionOutcome1.Likelihood > 0.64999997615814209)
          num5 *= (float) (1.6000000238418579 * (1.2000000476837158 - (double) decisionOutcome1.Likelihood));
        if (calculateRelationshipEffect && decisionOutcome1.SponsorClan != null)
        {
          float num6 = MathF.Lerp(0.2f, 1.8f, (float) (1.0 - (double) (int) (100.0 - (double) MathF.Clamp((float) clan.Leader.GetRelation(decisionOutcome1.SponsorClan.Leader), -100f, 100f)) / 200.0));
          num5 *= num6;
        }
        if ((double) num5 > (double) this.GetInfluenceCostOfSupport(supporter.Clan, Supporter.SupportWeights.FullyPush))
          supportWeight = Supporter.SupportWeights.FullyPush;
        else if ((double) num5 > (double) this.GetInfluenceCostOfSupport(supporter.Clan, Supporter.SupportWeights.StronglyFavor))
          supportWeight = Supporter.SupportWeights.StronglyFavor;
        else if ((double) num5 > (double) this.GetInfluenceCostOfSupport(supporter.Clan, Supporter.SupportWeights.SlightlyFavor))
          supportWeight = Supporter.SupportWeights.SlightlyFavor;
      }
      while (supportWeight >= Supporter.SupportWeights.SlightlyFavor && supporter.Clan != null && (double) supporter.Clan.Influence < (double) this.GetInfluenceCostOfSupport(supporter.Clan, supportWeight))
        --supportWeight;
      supportWeightOfSelectedOutcome = supportWeight;
      return supportWeight == Supporter.SupportWeights.StayNeutral || supportWeight == Supporter.SupportWeights.Choose ? (DecisionOutcome) null : decisionOutcome1;
    }

    public abstract float DetermineSupport(Clan clan, DecisionOutcome possibleOutcome);

    public abstract void DetermineSponsors(MBReadOnlyList<DecisionOutcome> possibleOutcomes);

    protected void AssignDefaultSponsor(DecisionOutcome outcome)
    {
      if (outcome.SupporterList.Count <= 0)
        return;
      Supporter.SupportWeights maxWeight = outcome.SupporterList.Max<Supporter, Supporter.SupportWeights>((Func<Supporter, Supporter.SupportWeights>) (t => t.SupportWeight));
      Supporter supporter = outcome.SupporterList.First<Supporter>((Func<Supporter, bool>) (t => t.SupportWeight == maxWeight));
      outcome.SetSponsor(supporter.Clan);
    }

    public abstract void ApplyChosenOutcome(DecisionOutcome chosenOutcome);

    public int GetInfluenceCost(
      DecisionOutcome decisionOutcome,
      Clan clan,
      Supporter.SupportWeights supportWeight)
    {
      int influenceCost = 0;
      switch (supportWeight)
      {
        case Supporter.SupportWeights.Choose:
          influenceCost = 0;
          break;
        case Supporter.SupportWeights.StayNeutral:
          influenceCost = 0;
          break;
        case Supporter.SupportWeights.SlightlyFavor:
          influenceCost = this.GetInfluenceCostOfSupport(clan, Supporter.SupportWeights.SlightlyFavor);
          break;
        case Supporter.SupportWeights.StronglyFavor:
          influenceCost = this.GetInfluenceCostOfSupport(clan, Supporter.SupportWeights.StronglyFavor);
          break;
        case Supporter.SupportWeights.FullyPush:
          influenceCost = this.GetInfluenceCostOfSupport(clan, Supporter.SupportWeights.FullyPush);
          break;
        default:
          Debug.FailedAssert("false", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\Election\\KingdomDecision.cs", nameof (GetInfluenceCost), 334);
          break;
      }
      return influenceCost;
    }

    public abstract TextObject GetSecondaryEffects();

    public abstract void ApplySecondaryEffects(
      MBReadOnlyList<DecisionOutcome> possibleOutcomes,
      DecisionOutcome chosenOutcome);

    public abstract TextObject GetChosenOutcomeText(
      DecisionOutcome chosenOutcome,
      KingdomDecision.SupportStatus supportStatus,
      bool isShortVersion = false);

    public MBList<DecisionOutcome> SortDecisionOutcomes(
      MBReadOnlyList<DecisionOutcome> possibleOutcomes)
    {
      return possibleOutcomes.OrderByDescending<DecisionOutcome, float>((Func<DecisionOutcome, float>) (k => k.InitialMerit)).ToMBList<DecisionOutcome>();
    }

    public abstract DecisionOutcome GetQueriedDecisionOutcome(
      MBReadOnlyList<DecisionOutcome> possibleOutcomes);

    public bool IsSingleClanDecision() => this.Kingdom.Clans.Count == 1;

    public virtual float CalculateRelationshipEffectWithSponsor(Clan clan)
    {
      float num = 0.8f;
      return (float) clan.Leader.GetRelation(this.ProposerClan.Leader) * num;
    }

    public int GetInfluenceCostOfSupport(Clan clan, Supporter.SupportWeights supportWeight)
    {
      int ofSupportInternal = this.GetInfluenceCostOfSupportInternal(supportWeight);
      float num = 1f;
      if (clan.Leader.GetPerkValue(DefaultPerks.Charm.FlexibleEthics))
        num += DefaultPerks.Charm.FlexibleEthics.PrimaryBonus;
      return (int) ((double) ofSupportInternal * (double) num);
    }

    protected virtual int GetInfluenceCostOfSupportInternal(Supporter.SupportWeights supportWeight)
    {
      switch (supportWeight)
      {
        case Supporter.SupportWeights.Choose:
        case Supporter.SupportWeights.StayNeutral:
          return 0;
        case Supporter.SupportWeights.SlightlyFavor:
          return 20;
        case Supporter.SupportWeights.StronglyFavor:
          return 60;
        case Supporter.SupportWeights.FullyPush:
          return 150;
        default:
          throw new ArgumentOutOfRangeException(nameof (supportWeight), (object) supportWeight, (string) null);
      }
    }

    public virtual bool OnShowDecision() => true;

    public virtual KingdomDecision GetFollowUpDecision() => (KingdomDecision) null;

    public enum SupportStatus
    {
      Equal,
      Majority,
      Minority,
    }
  }
}
